﻿using UnityEngine;
using UnityEngine.EventSystems;

namespace BToolkit.ExeUtils
{
    public class DragMoveScaleRotate : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
    {
        public bool moveByTwoFinger = false;
        public bool canMove = true;
        public bool canScale = true;
        public bool canRotate = true;

        RectTransform rectTransform;
        int finger1Id = -1, finger2Id = -1;
        Vector2 touchPreviousPos, moveDelta;
        Vector3 touchDownScale;
        float touchDownDis, rotateDelta, touchPreviousRadian;
        float moveThreshold = 0.1f, rotateThreshold = 0.1f;
        Canvas _canvas;
        Canvas canvas { get { return _canvas ?? (_canvas = GetComponentInParent<Canvas>()); } }

        void Awake()
        {
            rectTransform = transform as RectTransform;
            if (Application.isEditor)
            {
                moveByTwoFinger = false;
                BButton btn = GetComponent<BButton>() ?? gameObject.AddComponent<BButton>();
                btn.canTriggerInterval = 0;
                btn.AddDown(() =>
                {
                    moveDelta = Vector2.zero;
                    rotateDelta = 0;
                    finger1Id = 0;
                    touchPreviousPos = BUtils.ScreenToUGUIPoint(Input.mousePosition, canvas);
                });
                btn.AddUp(() =>
                {
                    finger1Id = -1;
                });
            }
        }

        public void OnPointerDown(PointerEventData eventData)
        {
            if (finger1Id == -1)
            {
                moveDelta = Vector2.zero;
                rotateDelta = 0;
                finger1Id = eventData.pointerId;
                if (!moveByTwoFinger)
                {
                    touchPreviousPos = BUtils.ScreenToUGUIPoint(eventData.position, canvas);
                }
            }
            else if (finger2Id == -1)
            {
                finger2Id = eventData.pointerId;
                if (finger1Id != -1)
                {
                    Vector2 pos1 = Vector2.zero, pos2 = Vector2.zero;
                    for (int i = 0; i < Input.touchCount; i++)
                    {
                        Touch touch = Input.GetTouch(i);
                        if (touch.fingerId == finger1Id)
                        {
                            pos1 = BUtils.ScreenToUGUIPoint(touch.position, canvas);
                        }
                        else if (touch.fingerId == finger2Id)
                        {
                            pos2 = BUtils.ScreenToUGUIPoint(touch.position, canvas);
                        }
                    }
                    touchDownScale = transform.localScale;
                    touchDownDis = Vector2.Distance(pos1, pos2);
                    touchPreviousRadian = Mathf.Atan2(pos2.y - pos1.y, pos2.x - pos1.x);
                }
            }
        }

        public void OnPointerUp(PointerEventData eventData)
        {
            if (finger1Id == eventData.pointerId)
            {
                finger1Id = -1;
            }
            else if (finger2Id == eventData.pointerId)
            {
                finger2Id = -1;
            }
        }

        void Update()
        {
            if (canMove && !moveByTwoFinger)
            {
                if (finger1Id != -1)
                {
                    if (Application.isEditor)
                    {
                        Vector2 pos = BUtils.ScreenToUGUIPoint(Input.mousePosition, canvas);
                        moveDelta = pos - touchPreviousPos;
                        touchPreviousPos = pos;
                    }
                    else
                    {
                        for (int i = 0; i < Input.touchCount; i++)
                        {
                            Touch touch = Input.GetTouch(i);
                            if (touch.fingerId == finger1Id)
                            {
                                Vector2 pos = BUtils.ScreenToUGUIPoint(touch.position, canvas);
                                moveDelta = pos - touchPreviousPos;
                                touchPreviousPos = pos;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    moveDelta += (Vector2.zero - moveDelta) * moveThreshold;
                }
                rectTransform.anchoredPosition += moveDelta;
            }
            if (finger1Id != -1 && finger2Id != -1)
            {
                Vector2 pos1 = Vector2.zero, pos2 = Vector2.zero;
                for (int i = 0; i < Input.touchCount; i++)
                {
                    Touch touch = Input.GetTouch(i);
                    if (touch.fingerId == finger1Id)
                    {
                        pos1 = BUtils.ScreenToUGUIPoint(touch.position, canvas);
                    }
                    else if (touch.fingerId == finger2Id)
                    {
                        pos2 = BUtils.ScreenToUGUIPoint(touch.position, canvas);
                    }
                }
                if (canMove && moveByTwoFinger)
                {
                    moveDelta = pos1 - touchPreviousPos;
                    touchPreviousPos = pos1;
                    rectTransform.anchoredPosition += moveDelta;
                }
                if (canScale)
                {
                    float currTouchDis = Vector2.Distance(pos1, pos2);
                    transform.localScale = touchDownScale * currTouchDis / touchDownDis;
                }
                if (canRotate)
                {
                    float currTouchRadian = Mathf.Atan2(pos2.y - pos1.y, pos2.x - pos1.x);
                    rotateDelta = currTouchRadian - touchPreviousRadian;
                    touchPreviousRadian = currTouchRadian;
                    transform.Rotate(0, 0, rotateDelta * 180 / Mathf.PI);
                }
            }
            else
            {
                if (canMove && moveByTwoFinger)
                {
                    moveDelta += (Vector2.zero - moveDelta) * moveThreshold;
                    rectTransform.anchoredPosition += moveDelta;
                }
                if (canRotate)
                {
                    rotateDelta += (0 - rotateDelta) * rotateThreshold;
                    transform.Rotate(0, 0, rotateDelta * 180 / Mathf.PI);
                }
            }
        }
    }
}